package com.youlai.system.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.youlai.system.common.base.BaseQuery;
import com.youlai.system.converter.ScoreConverter;
import com.youlai.system.mapper.SysScoreMapper;
import com.youlai.system.model.entity.SysScore;
import com.youlai.system.model.entity.SysUser;
import com.youlai.system.model.form.ScoreForm;
import com.youlai.system.model.query.ScorePageQuery;
import com.youlai.system.model.query.UserScoreCountPageQuery;
import com.youlai.system.model.vo.*;
import com.youlai.system.service.SysScoreService;
import com.youlai.system.service.SysUserService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * 课程成绩业务处理实现
 */
@Service
@RequiredArgsConstructor
public class SysScoreServiceImpl extends ServiceImpl<SysScoreMapper, SysScore> implements SysScoreService {

    private final ScoreConverter scoreConverter;

    private final SysUserService userService;

    @Override
    public SysScore getBy(String checkDate, Long studentId, Long courseId) {
        LambdaQueryWrapper<SysScore> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(SysScore::getCheckDate, checkDate).eq(SysScore::getStudentId, studentId).eq(SysScore::getCourseId, courseId);
        return getOne(queryWrapper);
    }

    @Override
    public SysScore getBy(String checkDate, String checkTime, Long studentId, Long courseId) {
        LambdaQueryWrapper<SysScore> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(SysScore::getCheckDate, checkDate).eq(SysScore::getCheckTime, checkTime).eq(SysScore::getStudentId, studentId).eq(SysScore::getCourseId, courseId);
        return getOne(queryWrapper);
    }

    @Override
    public IPage<ScorePageVO> getScorePage(ScorePageQuery queryParams) {
        // 参数构建
        int pageNum = queryParams.getPageNum();
        int pageSize = queryParams.getPageSize();
        Page<ScorePageVO> page = new Page<>(pageNum, pageSize);
        // 查询数据
        Page<ScorePageVO> userPage = this.baseMapper.getScorePage(page, queryParams);
        // 实体转换
        return userPage;
    }

    @Override
    public List<ScorePageVO> getScoreListByIdList(List<Long> scoreIdList) {
        return this.baseMapper.getScoreListByIdList(scoreIdList);
    }

    @Override
    public IPage<UserScoreCountPageVO> getUserScoreCountPage(UserScoreCountPageQuery queryParams) {
        // 参数构建
        int pageNum = queryParams.getPageNum();
        int pageSize = queryParams.getPageSize();
        Page<UserScoreCountPageVO> page = new Page<>(pageNum, pageSize);
        // 查询数据
        Page<UserScoreCountPageVO> userScoreCountPage = this.baseMapper.getUserScoreCountPage(page, queryParams);

        userScoreCountPage.getRecords().forEach(userScoreCountPageVO -> {
            String successRate = NumberUtil.decimalFormat("#.##%", userScoreCountPageVO.getSuccessCount().doubleValue() / userScoreCountPageVO.getTotalCount().doubleValue());
            userScoreCountPageVO.setSuccessRate(successRate);
        });
        // 实体转换
        return userScoreCountPage;
    }

    @Override
    public List<UserCourseScoreCountVO> getUserCourseScoreCountList(Long userId) {
        List<UserCourseScoreCountVO> userCourseScoreCountVOList = this.baseMapper.getUserCourseScoreCountList(userId);
        userCourseScoreCountVOList.forEach(userCourseScoreCountVO -> {
            if (StrUtil.isEmptyIfStr(userCourseScoreCountVO.getCategoryName())) {
                userCourseScoreCountVO.setCategoryName("无");
            }
            String successRate = NumberUtil.decimalFormat("#.##%", userCourseScoreCountVO.getSuccessCount().doubleValue() / userCourseScoreCountVO.getTotalCount().doubleValue());
            userCourseScoreCountVO.setSuccessRate(successRate);
        });
        return userCourseScoreCountVOList;
    }

    @Override
    public List<UserCategoryScoreCountVO> getUserCategoryScoreCountList(Long userId) {
        List<UserCategoryScoreCountVO> userCategoryScoreCountVOList = this.baseMapper.getUserCategoryScoreCountList(userId);
        userCategoryScoreCountVOList.forEach(userCategoryScoreCountVO -> {
            String successRate = NumberUtil.decimalFormat("#.##%", userCategoryScoreCountVO.getSuccessCount().doubleValue() / userCategoryScoreCountVO.getTotalCount().doubleValue());
            userCategoryScoreCountVO.setSuccessRate(successRate);
            if (StrUtil.isEmptyIfStr(userCategoryScoreCountVO.getCategoryName())) {
                userCategoryScoreCountVO.setCategoryName("无");
            }
        });
        return userCategoryScoreCountVOList;
    }

    @Override
    public boolean saveScore(Long studentId, ScoreForm scoreForm) {
        Long courseId = scoreForm.getCourseId();
        String today = StrUtil.isNotBlank(scoreForm.getExamDateTime()) ? scoreForm.getExamDateTime().substring(0, 10) : DateUtil.today();
        String time = StrUtil.isNotBlank(scoreForm.getExamDateTime()) ? scoreForm.getExamDateTime().substring(12, 16) : DateUtil.formatTime(DateUtil.date());
        long count = this.count(new LambdaQueryWrapper<SysScore>().eq(SysScore::getCheckDate, today).eq(SysScore::getStudentId, studentId).eq(SysScore::getCourseId, courseId));
        Assert.isTrue(count == 0, "成绩已存在");

        // 实体转换
        SysScore score = scoreConverter.form2Entity(scoreForm);
        score.setStudentId(studentId);
        score.setCheckDate(today);
        score.setCheckTime(time);
        DateTime dateTime = DateUtil.parse(score.getCheckDate() + " " + score.getCheckTime());
        score.setPlanTime(dateTime.toLocalDateTime());
        score.setRealTime(dateTime.toLocalDateTime());
        return save(score);
    }

    @Override
    public boolean updateScore(Long scoreId, Long studentId, ScoreForm scoreForm) {
        Long courseId = scoreForm.getCourseId();
        SysScore entity = this.getOne(new LambdaQueryWrapper<SysScore>().eq(SysScore::getStudentId, studentId).eq(SysScore::getCourseId, courseId).eq(SysScore::getId, scoreId));
        Assert.isTrue(entity != null, "没有找到相关成绩数据");
        // 实体转换
        SysScore score = scoreConverter.form2Entity(scoreForm);
        score.setStudentId(studentId);

        if (StrUtil.isNotBlank(scoreForm.getExamDateTime())) {
            score.setCheckDate(scoreForm.getExamDateTime().substring(0, 10));
            score.setCheckTime(scoreForm.getExamDateTime().substring(12, 16));
            DateTime dateTime = DateUtil.parse(score.getCheckDate() + " " + score.getCheckTime());
            score.setPlanTime(dateTime.toLocalDateTime());
            score.setRealTime(dateTime.toLocalDateTime());
        } else {
            score.setCheckDate(entity.getCheckDate());
            score.setCheckTime(entity.getCheckTime());
            score.setPlanTime(entity.getPlanTime());
            score.setRealTime(entity.getRealTime());
        }


        // 修改成绩
        return this.updateById(score);
    }

    @Override
    public ScoreForm getScoreForm(Long scoreId) {
        SysScore entity = this.getById(scoreId);
        SysUser user = userService.getById(entity.getStudentId());
        ScoreForm scoreForm = scoreConverter.entity2Form(entity);
        if (user != null) {
            scoreForm.setStudentCode(user.getUsername());
        }
        scoreForm.setExamDateTime(DateUtil.formatLocalDateTime(entity.getRealTime()));
        return scoreForm;
    }

    @Override
    public boolean deleteScores(String idsStr) {
        Assert.isTrue(StrUtil.isNotBlank(idsStr), "成绩删除数据为空");
        //
        List<Long> ids = new ArrayList<>();
        for (String id : idsStr.split(",")) {
            Long parseLong = Long.parseLong(id);
            ids.add(parseLong);
        }

        // 删除成绩
        return this.removeByIds(ids);
    }

    @Override
    public List<CategoryScoreCountVO> getAllCategoryScoreCountList() {
        List<CategoryScoreCountVO> categoryScoreCountVOList = this.baseMapper.getAllCategoryScoreCountList();
        categoryScoreCountVOList.forEach(categoryScoreCountVO -> {
            String successRate = NumberUtil.decimalFormat("#.##%", categoryScoreCountVO.getSuccessCount().doubleValue() / categoryScoreCountVO.getTotalCount().doubleValue());
            categoryScoreCountVO.setSuccessRate(successRate);
        });
        return categoryScoreCountVOList;
    }

    @Override
    public Map<Long, CategoryScoreCountVO> getAllCategoryScoreCountMap() {
        return getAllCategoryScoreCountList().stream().collect(Collectors.toMap(CategoryScoreCountVO::getCategoryId, it -> it));
    }

    @Override
    public List<CourseScoreCountVO> getAllCourseScoreCountList(BaseQuery baseQuery) {
        List<CourseScoreCountVO> courseScoreCountVOList = this.baseMapper.getAllCourseScoreCountList(baseQuery);
        courseScoreCountVOList.forEach(courseScoreCountVO -> {
            String successRate = NumberUtil.decimalFormat("#.##%", courseScoreCountVO.getSuccessCount().doubleValue() / courseScoreCountVO.getTotalCount().doubleValue());
            courseScoreCountVO.setSuccessRate(successRate);
            Double successPercent = Double.valueOf(NumberUtil.decimalFormat("#.##", courseScoreCountVO.getSuccessCount().doubleValue() * 100D / courseScoreCountVO.getTotalCount().doubleValue()));
            Double failPercent = Double.valueOf(NumberUtil.decimalFormat("#.##", courseScoreCountVO.getFailCount().doubleValue() * 100D / courseScoreCountVO.getTotalCount().doubleValue()));
            courseScoreCountVO.setSuccessPercent(successPercent);
            courseScoreCountVO.setFailPercent(failPercent);
        });
        return courseScoreCountVOList;
    }

    @Override
    public Map<Long, CourseScoreCountVO> getAllCourseScoreCountMap() {
        return getAllCourseScoreCountList(new BaseQuery()).stream().collect(Collectors.toMap(CourseScoreCountVO::getCourseId, it -> it));
    }

    @Override
    public List<LocationScoreCountVO> getAllLocationScoreCountList(BaseQuery baseQuery) {
        List<LocationScoreCountVO> locationScoreCountVOList = this.baseMapper.getAllLocationScoreCountList(baseQuery);
        locationScoreCountVOList.forEach(locationScoreCountVO -> {
            String successRate = NumberUtil.decimalFormat("#.##%", locationScoreCountVO.getSuccessCount().doubleValue() / locationScoreCountVO.getTotalCount().doubleValue());
            locationScoreCountVO.setSuccessRate(successRate);
        });
        return locationScoreCountVOList;
    }

    @Override
    public Map<Long, LocationScoreCountVO> getAllLocationScoreCountMap() {
        return getAllLocationScoreCountList(new BaseQuery()).stream().collect(Collectors.toMap(LocationScoreCountVO::getLocationId, it -> it));
    }

    @Override
    public List<MeasureScoreCountVO> getAllMeasureScoreCountList(BaseQuery baseQuery) {
        List<MeasureScoreCountVO> measureScoreCountVOList = this.baseMapper.getAllMeasureScoreCountList(baseQuery);
        measureScoreCountVOList.forEach(measureScoreCountVO -> {
            String successRate = NumberUtil.decimalFormat("#.##%", measureScoreCountVO.getSuccessCount().doubleValue() / measureScoreCountVO.getTotalCount().doubleValue());
            measureScoreCountVO.setSuccessRate(successRate);
        });
        return measureScoreCountVOList;
    }

    @Override
    public Map<Long, MeasureScoreCountVO> getAllMeasureScoreCountMap() {
        return getAllMeasureScoreCountList(new BaseQuery()).stream().collect(Collectors.toMap(MeasureScoreCountVO::getMeasureId, it -> it));
    }

    @Override
    public List<QuestionScoreCountVO> getAllQuestionScoreCountList(BaseQuery baseQuery) {
        List<QuestionScoreCountVO> questionScoreCountVOList = this.baseMapper.getAllQuestionScoreCountList(baseQuery);
        questionScoreCountVOList.forEach(questionScoreCountVO -> {
            String successRate = NumberUtil.decimalFormat("#.##%", questionScoreCountVO.getSuccessCount().doubleValue() / questionScoreCountVO.getTotalCount().doubleValue());
            questionScoreCountVO.setSuccessRate(successRate);
        });
        return questionScoreCountVOList;
    }

    @Override
    public Map<Long, QuestionScoreCountVO> getAllQuestionScoreCountMap() {
        return getAllQuestionScoreCountList(new BaseQuery()).stream().collect(Collectors.toMap(QuestionScoreCountVO::getQuestionId, it -> it));
    }

    @Override
    public boolean courseHasUsed(List<Long> courseIdList) {
        LambdaQueryWrapper<SysScore> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(SysScore::getCourseId, courseIdList);
        return count(queryWrapper) > 0;
    }

    @Override
    public boolean locationHasUsed(List<Long> locationIdList) {
        LambdaQueryWrapper<SysScore> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(SysScore::getLocationId, locationIdList);
        return count(queryWrapper) > 0;
    }

    @Override
    public boolean measureHasUsed(List<Long> measureIdList) {
        LambdaQueryWrapper<SysScore> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(SysScore::getMeasureId, measureIdList);
        return count(queryWrapper) > 0;
    }

    @Override
    public boolean questionHasUsed(List<Long> questionIdList) {
        LambdaQueryWrapper<SysScore> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(SysScore::getQuestionId, questionIdList);
        return count(queryWrapper) > 0;
    }

    @Override
    public boolean userHasUsed(List<Long> userIdList) {
        LambdaQueryWrapper<SysScore> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(SysScore::getStudentId, userIdList);
        return count(queryWrapper) > 0;
    }

    @Override
    public Long scorePassCount(BaseQuery baseQuery) {
        LambdaQueryWrapper<SysScore> queryWrapper = new LambdaQueryWrapper<>();
        if (baseQuery.getLoginUserId() != null) {
            queryWrapper.eq(SysScore::getStudentId, baseQuery.getLoginUserId());
        }
        queryWrapper.eq(SysScore::getScore, 100);
        return count(queryWrapper);
    }

    @Override
    public List<SysScore> get4ScoreList(Long userId, Long courseId) {
        return getNumScoreList(userId, courseId, 4);
    }

    @Override
    public List<SysScore> getNumScoreList(Long userId, Long courseId, Integer number) {
        LambdaQueryWrapper<SysScore> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysScore::getStudentId, userId).eq(SysScore::getCourseId, courseId).eq(SysScore::getHasUsed, 0);
        queryWrapper.isNotNull(SysScore::getScore);
        queryWrapper.orderByAsc(SysScore::getRealTime);
        List<SysScore> scoreList = list(queryWrapper);
        return scoreList.size() >= number ? scoreList.subList(0, number) : scoreList;
    }

    @Override
    public SysScore getMinOneScore(Long userId, Long courseId) {
        List<SysScore> scoreList = get4ScoreList(userId, courseId);
        return scoreList.size() > 0 ? scoreList.get(0) : null;
    }

    @Override
    public List<SysScore> getScoreList(Long userId, Long courseId, LocalDateTime maxTime) {
        LambdaQueryWrapper<SysScore> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysScore::getStudentId, userId).eq(SysScore::getCourseId, courseId).eq(SysScore::getHasUsed, 0);
        if (maxTime != null) {
            queryWrapper.lt(SysScore::getRealTime, maxTime);
        }
        queryWrapper.isNotNull(SysScore::getScore);
        queryWrapper.orderByDesc(SysScore::getRealTime);
        return list(queryWrapper);
    }

    @Override
    public List<SysScore> getPrimaryDegreeScoreList(Long userId, Long courseId, LocalDateTime maxTime) {
        LambdaQueryWrapper<SysScore> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysScore::getStudentId, userId).eq(SysScore::getCourseId, courseId).eq(SysScore::getHasUsed, 1).le(SysScore::getRealTime, maxTime);
        queryWrapper.isNotNull(SysScore::getScore);
        queryWrapper.orderByDesc(SysScore::getRealTime);
        return list(queryWrapper);
    }

    @Override
    public List<SysScore> getPrimayPeriodScoreList(Long userId, List<Long> scoreIdList) {
        LambdaQueryWrapper<SysScore> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysScore::getStudentId, userId).in(SysScore::getId, scoreIdList).eq(SysScore::getHasUsed, 1);
        queryWrapper.isNotNull(SysScore::getScore);
        queryWrapper.orderByDesc(SysScore::getRealTime);
        return list(queryWrapper);
    }

    @Override
    public boolean updateHasUsedToZero(Long studentId, Long courseId) {
        LambdaUpdateWrapper<SysScore> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(SysScore::getStudentId, studentId).eq(SysScore::getCourseId, courseId);
        updateWrapper.set(SysScore::getHasUsed, 0);
        return update(updateWrapper);
    }

    @Override
    public boolean updateHasUsedToZeroByCourseId(Long courseId) {
        LambdaUpdateWrapper<SysScore> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(SysScore::getCourseId, courseId);
        updateWrapper.set(SysScore::getHasUsed, 0);
        return update(updateWrapper);
    }

    @Override
    public Long countByStudentIdAndCourseId(Long studentId, Long courseId) {
        LambdaQueryWrapper<SysScore> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysScore::getStudentId, studentId);
        queryWrapper.eq(SysScore::getCourseId, courseId);
        queryWrapper.eq(SysScore::getHasUsed, 0);
        return count(queryWrapper);
    }
}